package com.xlhl.mybatisplusplus.manage;

import com.baomidou.mybatisplus.core.batch.BatchMethod;
import com.baomidou.mybatisplus.core.batch.MybatisBatch;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 针对 Mybatis Plus 批量操作封装 Entity: 实体类型  OtherType: 待转换的类型
 * ByConvert 后缀就是多了一步：将其他数据类型转换为 实体类型的操作
 * 没有事务控制，需要事务需要自己操作
 *
 * @author xlhl
 */
@Component
public class MyBatisBatchManage {
    @Resource
    private SqlSessionFactory sqlSessionFactory;

    /**
     * 批量操作（不对外开放）
     *
     * @param dataList 数据列表（实体类型）
     * @param method   操作
     * @param <Entity> 数据库对应 Bean 类型
     * @return 执行结果列表
     */
    private <Entity> List<BatchResult> batchAction(List<Entity> dataList, BatchMethod<Entity> method) {
        if (dataList == null || dataList.isEmpty()) {
            return Collections.emptyList();
        }

        return new MybatisBatch<>(sqlSessionFactory, dataList).execute(method);
    }

    /**
     * 批量新增
     *
     * @param dataList    数据列表（实体类型）
     * @param mapperClass 实体对应 Mapper 的 class
     * @param <Entity>    数据库对应 Bean 类型
     * @return 执行结果列表
     */
    public <Entity> List<BatchResult> batchInsert(List<Entity> dataList, Class<? extends BaseMapper<Entity>> mapperClass) {
        return batchAction(dataList, new MybatisBatch.Method<Entity>(mapperClass).insert());
    }

    /**
     * 列表类型为其他类型的批量新增
     *
     * @param dataList    数据列表（非实体类型）
     * @param clazz       实体对应 Mapper 的 class
     * @param func        把 非实体类型转换为 实体类型
     * @param <OtherType> 其他数据类型
     * @param <Entity>    数据库对应 Bean 类型
     * @return 执行结果列表
     */
    public <OtherType, Entity> List<BatchResult> batchInsertByConvert(List<OtherType> dataList, Class<? extends BaseMapper<Entity>> clazz, Function<OtherType, Entity> func) {
        return batchInsert(convertList(dataList, func), clazz);
    }

    /**
     * 批量修改
     *
     * @param dataList    数据列表（实体类型）
     * @param mapperClass 实体对应 Mapper 的 class
     * @param <Entity>    数据库对应 Bean 类型
     * @return 执行结果列表
     */
    public <Entity> List<BatchResult> batchUpdate(List<Entity> dataList, Class<? extends BaseMapper<Entity>> mapperClass) {
        return batchAction(dataList, new MybatisBatch.Method<Entity>(mapperClass).updateById());
    }

    /**
     * 列表类型为其他类型的批量更新
     *
     * @param dataList    数据列表（非实体类型）
     * @param clazz       实体对应 Mapper 的 class
     * @param func        把 非实体类型转换为 实体类型
     * @param <OtherType> 其他数据类型
     * @param <Entity>    数据库对应 Bean 类型
     * @return 执行结果列表
     */
    public <OtherType, Entity> List<BatchResult> batchUpdateByConvert(List<OtherType> dataList, Class<? extends BaseMapper<Entity>> clazz, Function<OtherType, Entity> func) {
        return batchUpdate(convertList(dataList, func), clazz);
    }

    /**
     * 批量删除
     *
     * @param dataList    数据列表（实体类型）
     * @param mapperClass 实体对应 Mapper 的 class
     * @param <Entity>    数据库对应 Bean 类型
     * @return 执行结果列表
     */
    public <Entity> List<BatchResult> batchDelete(List<Entity> dataList, Class<? extends BaseMapper<Entity>> mapperClass) {
        return batchAction(dataList, new MybatisBatch.Method<Entity>(mapperClass).deleteById());
    }

    /**
     * 列表类型为其他类型的批量删除
     *
     * @param dataList    数据列表（非实体类型）
     * @param clazz       实体对应 Mapper 的 class
     * @param func        把 非实体类型转换为 实体类型
     * @param <OtherType> 其他数据类型
     * @param <Entity>    数据库对应 Bean 类型
     * @return 执行结果列表
     */
    public <OtherType, Entity> List<BatchResult> batchDeleteByConvert(List<OtherType> dataList, Class<? extends BaseMapper<Entity>> clazz, Function<OtherType, Entity> func) {

        return batchDelete(convertList(dataList, func), clazz);
    }

    /**
     * 列表转换 OtherType -> Entity
     *
     * @param list        其他数据类型列表
     * @param func        转化函数
     * @param <OtherType> 其他数据类型
     * @param <Entity>    数据库对应 Bean 类型
     * @return 执行结果列表
     */
    private <OtherType, Entity> List<Entity> convertList(List<OtherType> list, Function<OtherType, Entity> func) {
        return list.stream().map(func).collect(Collectors.toList());
    }
}














